<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
	<head>
		<title>JavaScript Inheritance, Constructor & Prototype</title>
		<style type="text/css">
			div#header {
				color: #0066FF;
				font-size: 25pt;
			}
			
			div#content {
				color: #B088FF;
				font-size: 12pt;
			}
			
			p#subtitle {
				color: black;
				font-size: 10pt;
			}
			
			strong#globalBaseDetailName {
				color: #FFAA33;
				font-size: 15pt;
			}
		</style>
		
		<!-- embed jquery by google，藉由google嵌入jquery 1.4.4 -->
		<script type="text/javascript" src="http://www.google.com/jsapi"></script>
		<script type="text/javascript" language="javascript">
			google.load( "jquery", "1.4.4" );
		</script>
		<script type="text/javascript">
			
			// global variables
			var globalBase;
			var globalDerived; 
			
			var GlobalBase = function( base ) {
				this.globalBase = base;
				this.getGlobalBase = function() {
					return this.globalBase;
				};
				this.setGlobalBase = function( base ) {
					this.globalBase = base;
				};
			};
			
			var GlobalDerived = function( derived ) {
				this.globalDerived = derived;
				this.getGlobalDerived = function() {
					return this.globalDerived;
				};
				this.setGlobalDerived = function( derived ) {
					this.globalDerived = derived;
				};
			};
			
			// 父類別建構子函式
			var Base = function() {
				this.getDetailName = function() {
					return this.detailInfo.name;
				};
				this.detailInfo = {
					name: "base",
					width: 550,
					height: 250,
					left: "30%",
					top: "25%"
				};
				
				var innerThis = this;  // 小心，javascript的this參照與closure
				this.toString = function() {
					
					alert(
						"In toString, innerThis.getDetailName(): " + innerThis.getDetailName() + "\n" + 
						"In toString, innerThis.detailInfo.width: " + innerThis.detailInfo.width + "\n" + 
						"In toString, innerThis.detailInfo.height: " + innerThis.detailInfo.height + "\n" + 
						"In toString, innerThis.detailInfo.left: " + innerThis.detailInfo.left + "\n" + 
						"In toString, innerThis.detailInfo.top: " + innerThis.detailInfo.top
					);
					
					var returnString = 
						"<br />detailInfo name: " + innerThis.getDetailName() + "<br />" +
						"detailInfo width: " + innerThis.detailInfo.width + "<br />" +
						"detailInfo height: " + innerThis.detailInfo.height + "<br />" +
						"detailInfo left: " + innerThis.detailInfo.left + "<br />" +
						"detailInfo top: " + innerThis.detailInfo.top;
						
					return returnString;
				};
			};
				
			/*
			Base.prototype.detailInfo = {
				name: "base",
				width: 500,
				height: 250,
				left: "30%",
				top: "25%"
			};
			*/
			
			Base.prototype.setName = function( name ) {
				this.detailInfo.name = name;
			};
			
			Base.prototype.setWidth = function( width ) {
				this.detailInfo.width = width;
			};
				
			Base.prototype.setHeight = function( height ) {
				this.detailInfo.height = height;
			};
				
			Base.prototype.setLeft = function( left ) {
				this.detailInfo.left = left;
			};
				
			Base.prototype.setTop = function( top ) {
				this.detailInfo.top = top;
			};
				
			Base.prototype.setDatailInfo = function( detailObj ) {
				this.prototype.detailInfo = detailObj;
			};
			
			// 子類別建構子函式
			var Derived = function( cssClassObj ) {
				if( cssClassObj == null || typeof( cssClassObj ) == "undefined" ) {
					throw new Error( "wrong argument: cssClassObj!" );
				}

				this.cssClass = cssClassObj;
				var innerThis = this;
				
				this.getCssClass = function() {
					return this.cssClass;
				};
				this.setCssClass = function( cssObj ) {
					innerThis.cssClass = cssObj;
				};
			};
			
			Derived.prototype.setCssAttribute = function( cssAttrName, cssAttrValue ) {
				if( typeof( cssAttrName ) != "string" || typeof( cssAttrValue ) != "string" ) {
					throw new Error( "wrong argument: type mismatch! must be string type!" );
				}
				
				var css = this.getCssClass();
				css[cssAttrName] = cssAttrValue;
				this.setCssAttribute( css );
			};
			
			
			/***************************************************************************************/

			
			// 顯示 globalBase 目前的 detailInfo.name
			function showGlobalNameOnLabel( detailName ) {
				if( detailName == null || typeof( detailName ) == "undefined" ) {
					throw new Error( "wrong argument: detailName!" );
				}
			
				$( "#lblGlobalBaseName" ).html(	"<strong>" + detailName + "</strong>" );
			}
			
			// 改變 globalBase 的detailInfo.name
			function changeBaseDetailName( detailName ) {
				if( detailName == null || typeof( detailName ) == "undefined" ) {
					throw new Error( "the argument detailName is wrong!" );
				}
				
				if( detailName == "" ) {
					globalBase.getGlobalBase().setName( "" );
				}
				
				// alert( "change detailName: " + detailName );
				globalBase.getGlobalBase().setName( detailName );
				showGlobalNameOnLabel( detailName );
			}
			
			// 產生Base函式物件的工廠
			function baseInstanceFactory() {
				var baseModel = new Base();
				// alert( "create a new Base object now!" );
				return baseModel;
			}
			
			// 產生Derived函式物件的工廠
			function derivedInstanceFactory() {
				var defaultCss = {
					backgroundColor: "black",
					color: "white"
				};
				var derivedObj = new Derived( defaultCss );
				// alert( "create a new Derived object now!" );
				return derivedObj;
			}
			
			// 顯示Derived物件的詳細內容
			function showDerivedDetails( derivedObj ) {
				// alert( derivedObj );
				
				
				/*
				alert( globalDerived.getGlobalDerived() );
				
				var name = globalDerived.getGlobalDerived().getDetailName();
				
				alert( name );
				*/
				
				
				var derivedDetailsStr = derivedObj.toString();
				
				alert( derivedDetailsStr );
				
				$( "#derivedShowDetail" ).after( derivedDetailsStr );
			}
			
			$( document ).ready( function() {
				globalBase = new GlobalBase( baseInstanceFactory() );
				
				// 宣告Derived物件的原型是Base
				Derived.prototype = globalBase;   // 20110803 bug here
				
				
				// alert( $( "form > input[type='button']" ).attr( "value" ) ); 
				$( "form > input[type='button']" ).click( function() {
					var globalBaseName = globalBase.getGlobalBase().getDetailName();
					$( "#lblGlobalBaseName" ).html(	"<strong>" + globalBaseName + "</strong>" );
				});
				
				$( "select[title~='Model']" ).change( function() {
					var styleName = $( this ).children( ":selected" ).attr( "value" );
					changeBaseDetailName( styleName );
					
				});
				
				$( "#createDerived" ).click( function() {
					var derived = derivedInstanceFactory();
					globalDerived = new GlobalDerived( derived );  // 小心，這是global variable
					// 不能用local variable的原因是，生命週期
				});
				
				$( "#derivedShowDetail" ).click( function() {
					showDerivedDetails( globalDerived.getGlobalDerived() );
				});
				
			});  // end of ready() function
		</script>
		
	</head>
	
	<body>
		<div title="temp1" id="header">
			JavaScript Prototype, Constructor & Inheritance small Lab
		</div>
		<p id="subtitle">2011/08/03 by Pony Lin</p>
		<div title="temp1" id="content">
			<form name="testing" id="easy">
				<label title="click the button" value="Please click the following button">Please click the following button</label><br />
				<input type="button" value="Show the GlobalBase style name" /><br />
				Choose a style name of GlobalBase
				<select title="Base Model">
					<option value="" selected="selected">Style of Base Model</option>
					<option value="base">Base</option>
					<option value="star">Star</option>
					<option value="sky">Sky</option>
					<option value="ocean">Ocean</option>
				</select><br />
				<label>Now the global detail name is</label>
				<label title="Style Name of GlobalBase" id="lblGlobalBaseName"></label>
				<br />
				<br />
				<label title="Choose the width" value="Choose the Width">Choose the Width: </label>
				<input type="radio" value="550" name="detailWidth" />550 px&nbsp;
				<input type="radio" value="350" name="detailWidth" />350 px&nbsp;
				<input type="radio" value="250" name="detailWidth" />250 px
			</form>
		</div>
		<button id="createDerived">Create Derived</button><br />
		<button id="derivedShowDetail">Show Derived Details</button><br /> 
    <label id="lblBaseCounter"></label><br />
    <label id="lblDerivedCounter"></label><br />  
	</body>
</html>